//arrfun4.cpp -- functions with an array range
//arrobj.cpp -- functions with array objects (C++11)
//recur.cpp -- using recursion
//arfupt.cpp -- an array of function pointers
//strctptr.cpp -- function with pointer to structure arguments

#include <iostream>
#include <array>
#include <string>

//constant data
const int Seasons = 4;
const std::array<std::string, Seasons> Snames =
{ "Spring","Summer","Fall","Winter" };

//function to modify array object
void fill(std::array<double, Seasons> * pa);
//function that uses array object without modifying it
void show(std::array<double, Seasons> da);
void Example_7_15();

void Example_7_16(int n);  //call the recursive function


const int ArSize = 8;
void test();
void Example_7_8();
int Example_7_8_sum_arr(const int * begin, const int * end);

//various notations, same signatures
const double * f1(const double ar[], int n);
const double * f2(const double [], int n);
const double * f3(const double *, int n);
void Example_7_19();

void Example_7_13();

//structure templates
struct polar
{
	double distance;	//distance from origin
	double angle;		//direction from origin
};

struct rect
{
	double x;
	double y;
};

//prototype
void rect_to_polar(const rect * pxy, polar * pda);
void show_polar(const polar *pda);

//int main()
//{
//	Example_7_13();
//	//Example_7_19();
//	//Example_7_16(4);
//	//test();
//	//Example_7_8();
//	return 0;
//}

void Example_7_8()
{
	using namespace std;
	int cookies[ArSize]{ 1,2,4,8,16,32,64,128 };
	//some system require preceding int with static to 
	//enable array initialization

	int sum = Example_7_8_sum_arr(cookies, cookies + ArSize);
	cout << "Total cookies eaten: " << sum << endl;
	sum = Example_7_8_sum_arr(cookies, cookies + 3);//first 3 elements
	cout << "First three eaters ate " << sum << " cookies.\n";
	sum = Example_7_8_sum_arr(cookies + 4, cookies + 8);
	cout << "Last four eaters ate " << sum << " cookies.\n";
	return;
}

//return the sum of an integer array 
int Example_7_8_sum_arr(const int * begin, const int * end)
{
	const int * pt;
	int total = 0;

	for (pt = begin; pt != end; pt++)
	{
		total = total + *pt;
//		*pt += 1; invaild
	}
		
	return total;
}

void Example_7_15()
{
	std::array<double, Seasons> expenses;
	fill(&expenses);
	show(expenses);
	return;
}

//function to modify array object
void fill(std::array<double, Seasons> * pa)
{
	using namespace std;
	for (int i = 0; i < Seasons; i++)
	{
		cout << "Enter " << Snames[i] << " expense: ";
		cin >> (*pa)[i];
	}
}
//function that uses array object without modifying it
void show(std::array<double, Seasons> da)
{
	using namespace std;
	double total = 0.0;
	cout << "\nExpenses\n";
	for (int i = 0; i < Seasons; i++)
	{
		cout << Snames[i] << ": $" << da[i] << endl;
		total += da[i];
	}
	cout << "Total Expenses: $" << total << endl;
}

void Example_7_16(int n)
{
	using namespace std;
	cout << "Counting down ... " << n << endl;
	if (n > 0)
		Example_7_16(n - 1); // function calls itself
	cout << n << "Kaboom! \n";
	return;
}



void test()
{
	using namespace std;
	int age = 39;
	const int * pt = &age;
	cout << pt << endl;
	int sage = 80;
	pt = &sage;
	cout << pt << endl;
	//*pt = 90;
	cout << *pt << endl;
	return;
}

void Example_7_19()
{
	using namespace std;
	double av[3] = { 1112.3,1542.6,2227.9 };

	//pointer to a function 
	const double *(*p1)(const double *, int) = f1;
	auto p2 = f2;//C++11 automatic type deduction
	//pre-C++11 can use the following code instead
	//const double *(*p2)(const double *,int)= f2
	cout << "Using pointers to function:\n";
	cout << "Address Value\n";
	cout << (*p1)(av, 3) << ": " << *(*p1)(av, 3) << endl;
	cout << p2(av, 3) << ": " << *p2(av, 3) << endl;

	//pa an array of pointers
	//auto doesn't work with list initialization
	const double *(*pa[3])(const double *, int) = { f1,f2,f3 };
	//but it does work for initializing to a single value 
	//pb a pointer to first element of pa 
	auto pb = pa;
	//pre-C++11 can use the following code instead
	//const double *(**pb)(const double *,int)=pa;
	cout << "\nUsing an array of pointers to functions: \n";
	cout << "Address Value\n";
	for (int i = 0; i < 3; i++)
		cout << pa[i](av, 3) << ": " << *pa[i](av, 3) << endl;
	cout << "\nUsing a pointer to a pointer to a function:\n";
	cout << "Address Value\n";
	for (int i = 0; i < 3; i++)
		cout << pb[i](av, 3) << ": " << *pb[i](av, 3) << endl;

	//what about a pointer to an array of function pointers
	cout << "\nUsing pointers to an array of pointers:\n";
	cout << "Address Value\n";
	//easy way to declare pc
	auto pc = &pa;
	//pre-C++11 can use the following code instead
	//const double *(*(*pc)[3])(const double *, int )= &pa;
	cout << (*pc)[0](av, 3) << ": " << *(*pc)[0](av, 3) << endl;
	//hard way to declare pd
	const double *(*(*pd)[3])(const double *, int) = &pa;
	//store return value in pdb
	const double * pdb = (*pd)[1](av, 3);
	cout << pdb << ": " << *pdb << endl;
	//alternative notation
	cout << (*(*pd)[2])(av, 3) << ": " << *(*(*pd)[2])(av, 3) << endl;

	return;
}

//some rather dull function

const double * f1(const double ar[], int n)
{
	return ar;
}
const double * f2(const double ar[], int n)
{
	return ar + 1;
}
const double * f3(const double ar[], int n)
{
	return ar + 2;
}

void Example_7_13()
{
	using namespace std;
	rect rplace;
	polar pplace;
	cout << "Enter the x and y values: ";
	while ((cin >> rplace.x >> rplace.y) )
//	while ( (cin.get()!='\n'))
	{
		rect_to_polar(&rplace, &pplace);	//pass addresses
		show_polar(&pplace);				//pass addresses
		cout << "Next two numbers (q to quit): ";
	}
	cout << "Done.\n";
	return;
}

void rect_to_polar(const rect * pxy, polar * pda)
{
	using namespace std;
	pda->distance =
		sqrt(pxy->x*(*pxy).x + pxy->y*pxy->y);
	pda->angle = atan2(pxy->y, pxy->x);
	return;
}

void show_polar(const polar * pda)
{
	using namespace std;
	const double Rad_to_deg = 57.29577951;

	cout << "distance = " << pda->distance;
	cout << ", angle = " << pda->angle*Rad_to_deg;
	cout << " degrees\n";
	return;
}
